package client;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.CharacterData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import client.communication.Log;
import client.sharedRessources.Order;

class CellMES_Mediator
{
	private static CellMES_Mediator instance;
	private MESServer mesServer;
	
	private CellMES_Mediator()
	{
		 mesServer = new MESServer();
	}
	
	public static CellMES_Mediator getInstance()
	{
		if (instance == null)
			instance = new CellMES_Mediator();
		return instance;
	}
	
	void sendLog(Log log)
	{
		String returned = "";

		String xmlDoc =
				"POST /log HTTP/1.1\n"  +
				"Host: 192.168.0.100\n" + 
				"Content-Length: " + Helper.logXML(log).length() + "\n" +
				"Content-Type: text/html\n\n" + 
				Helper.logXML(log);
		
		do
		{
			returned = mesServer.sendCommandToMES(xmlDoc);
		} while (!returned.contains("HTTP/1.0 201 Created"));
	}
	
	Order getNewOrder()
	{
		String allOrders = "";

		String getOrders = "GET /orders HTTP/1.1"  +
						   "\nHost: 192.168.0.100";
		while (!allOrders.contains("HTTP/1.1 200 OK"))
		{
			allOrders = mesServer.sendCommandToMES(getOrders);
		}
		List<String> orderNumbers = Helper.getOrdersFromXML(allOrders);
		
		for (String orderNumber : orderNumbers)
		{
			String orderSpecs = "";
			String getOrder = "GET /orders/" + orderNumber + " HTTP/1.1"  +
							  "\nHost: 192.168.0.100";
			
			do
			{
				orderSpecs = mesServer.sendCommandToMES(getOrder);
			} while (!orderSpecs.contains("HTTP/1.1 200 OK"));
			
			if (orderSpecs.contains("ready"))
			{
				String orderConfirmed = "";
				String putOrder = "PUT /orders/" + orderNumber + " HTTP/1.1"  +
								  "\nHost: 192.168.0.100";
				
				do
				{
					orderConfirmed = mesServer.sendCommandToMES(putOrder);
				} while (!orderConfirmed.contains("HTTP/1.1 200 OK"));
				
				Order order = Helper.getOrderFromXMLs(orderNumber, orderSpecs, orderConfirmed);
				return order;
			}
		}
		return null;
	}
	
	void orderDone(String orderID, String orderTicket)
	{
		String returned = "";

		String xmlDoc = 
				"DELETE /orders/" + orderID + "/" + orderTicket + " HTTP/1.1"  +
				"\nHost: 192.168.0.100";
		
		do
		{
			returned = mesServer.sendCommandToMES(xmlDoc);
		} while (!returned.contains("HTTP/1.1 200 OK"));
	}
}

class Helper
{
	static String logXML(Log log)
	{
		try
		{
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
	 
			// root elements
			Document doc = docBuilder.newDocument();
			doc.setXmlStandalone(true);
			Element rootElement = doc.createElement("log_entry");
			doc.appendChild(rootElement);
	
			Element event = doc.createElement("event");
			event.appendChild(doc.createTextNode(log.getEventType()));
			rootElement.appendChild(event);
			
			Element time = doc.createElement("time");
			time.appendChild(doc.createTextNode(log.getTime()));
			rootElement.appendChild(time);
			
			Element cell_id = doc.createElement("cell_id");
			cell_id.appendChild(doc.createTextNode(Integer.toString(log.getCellId())));
			rootElement.appendChild(cell_id);
			
			Element comment = doc.createElement("comment");
			comment.appendChild(doc.createTextNode(log.getComment()));
			rootElement.appendChild(comment);
	 
			// transform the Document into a String
	        DOMSource domSource = new DOMSource(doc);
	        TransformerFactory tf = TransformerFactory.newInstance();
	        Transformer transformer = tf.newTransformer();
	        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
	        transformer.setOutputProperty(OutputKeys.ENCODING,"utf-8");
	        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
	        java.io.StringWriter sw = new java.io.StringWriter();
	        StreamResult sr = new StreamResult(sw);
	        transformer.transform(domSource, sr);
	        String xml = sw.toString();
	        return xml;
		}
		catch (TransformerException e)
		{ e.printStackTrace(); }
		catch ( ParserConfigurationException e)
		{ e.printStackTrace(); }
		return "";
	}
	
	public static List<String> getOrdersFromXML(String allOrders)
	{
		String[] t = allOrders.split("\n\n");
		String allOrdersXML = t[1].replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n", "");
		ArrayList<String> orders = new ArrayList<String>();

		try
		{
			DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		    InputSource is = new InputSource();
		    is.setCharacterStream(new StringReader(allOrdersXML));

		    Document doc = db.parse(is);
		    NodeList nodes = doc.getElementsByTagName("order");

            for(int i=0; i < nodes.getLength() ; i++)
            {
            	String orderURI = getCharacterDataFromElement((Element) nodes.item(i));
            	String[] orderSplitted = orderURI.split("/");
            	orders.add(orderSplitted[orderSplitted.length-1]);
            }
        }
		catch (SAXParseException err)
        { err.printStackTrace(); }
		catch (SAXException e)
		{ e.printStackTrace(); }
		catch (ParserConfigurationException pce)
		{ pce.printStackTrace(); }
		catch (IOException io)
		{ io.printStackTrace(); }
		
		return orders;
	}

	static Order getOrderFromXMLs(String orderID, String orderSpecs, String orderConfirmed)
	{
		String ticket = getTicket(orderConfirmed);
		Order order = null;

		String[] t = orderSpecs.split("\n\n");
		String orderSpecsXML = t[1].replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n", "");

		try
		{
			DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		    InputSource is = new InputSource();
		    is.setCharacterStream(new StringReader(orderSpecsXML));

		    Document doc = db.parse(is);
		    NodeList nodes = doc.getElementsByTagName("bricks");

	        Element element = (Element) nodes.item(0);

	        NodeList redNode = element.getElementsByTagName("red");
	        String red = getCharacterDataFromElement((Element) redNode.item(0));
	        NodeList blueNode = element.getElementsByTagName("blue");
	        String blue = getCharacterDataFromElement((Element) blueNode.item(0));
	        NodeList yellowNode = element.getElementsByTagName("yellow");
	        String yellow = getCharacterDataFromElement((Element) yellowNode.item(0));
	        
	        order = new Order(orderID, ticket, Integer.parseInt(red), Integer.parseInt(blue), Integer.parseInt(yellow));
        }
		catch (SAXParseException err)
        { err.printStackTrace(); }
		catch (SAXException e)
		{ e.printStackTrace(); }
		catch (ParserConfigurationException pce)
		{ pce.printStackTrace(); }
		catch (IOException io)
		{ io.printStackTrace(); }
		
		return order;
	}
	
	private static String getTicket(String orderConfirmed)
	{
		String[] t = orderConfirmed.split("\n\n");
		String ticketXML = t[1].replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n", "");
		try
		{
			DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		    InputSource is = new InputSource();
		    is.setCharacterStream(new StringReader(ticketXML));
	
		    Document doc = db.parse(is);
		    NodeList nodes = doc.getElementsByTagName("ticket");
	
        	return getCharacterDataFromElement((Element) nodes.item(0));
	    }
		catch (SAXParseException err)
	    { err.printStackTrace(); }
		catch (SAXException e)
		{ e.printStackTrace(); }
		catch (ParserConfigurationException pce)
		{ pce.printStackTrace(); }
		catch (IOException io)
		{ io.printStackTrace(); }
		return "";
	}

	private static String getCharacterDataFromElement(Element e)
	{
		Node child = e.getFirstChild();
	    if (child instanceof CharacterData)
	    {
	      CharacterData cd = (CharacterData) child;
	      return cd.getData();
	    }
	    return "";
	}
	
	static String orderDoneXML(String orderTicket)
	{
		try
		{
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
	 
			// root elements
			Document doc = docBuilder.newDocument();
			doc.setXmlStandalone(true);
			Element rootElement = doc.createElement("ticket");
			rootElement.appendChild(doc.createTextNode(orderTicket));
			doc.appendChild(rootElement);
	 
			// transform the Document into a String
	        DOMSource domSource = new DOMSource(doc);
	        TransformerFactory tf = TransformerFactory.newInstance();
	        Transformer transformer = tf.newTransformer();
	        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
	        transformer.setOutputProperty(OutputKeys.ENCODING,"utf-8");
	        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
	        java.io.StringWriter sw = new java.io.StringWriter();
	        StreamResult sr = new StreamResult(sw);
	        transformer.transform(domSource, sr);
	        String xml = sw.toString();
	        return xml;
		}
		catch (TransformerException e)
		{ e.printStackTrace(); }
		catch ( ParserConfigurationException e)
		{ e.printStackTrace(); }
		return "";
	}
}
